package com.ncr.travel.tas.configuration.service.messaging;

import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.annotation.Transactional;

import com.ncr.travel.tas.configuration.dao.ConfigurationDao;
import com.ncr.travel.tas.configuration.model.ConfigurationNode;
import com.ncr.travel.tas.configuration.model.ConfigurationValue;
import com.ncr.travel.tas.shared.configuration.ConfigurationServiceException;

@Transactional(readOnly = true)
public class ConfigurationServiceImpl implements ConfigurationService, InitializingBean {

	private ConfigurationDao configurationDao;

	private static final Logger logger = LoggerFactory.getLogger(ConfigurationServiceImpl.class);

	public void afterPropertiesSet() {

	}

	public ConfigurationServiceImpl(){
		
	}
	
	public ConfigurationServiceImpl(ConfigurationDao configurationDao,EntityManager entityManager 
			 ) {
		super();
		this.configurationDao = configurationDao;
		this.entityManager = entityManager;
	}

	public ConfigurationNode getConfiguration(long nodeId) throws ConfigurationServiceException {

		try {
			return this.getConfigurationDao().get(nodeId);
		} catch (Exception e) {
			logger.error("", e);
			throw new ConfigurationServiceException("Failed to retrieve ConfigurationNode " + nodeId, e);
		}

	}

	@Transactional
	public long addConfiguration(ConfigurationNode node) throws ConfigurationServiceException {

		try {
			this.getConfigurationDao().save(node);
		} catch (Exception e) {
			logger.error("", e);
			throw new ConfigurationServiceException("Failed to add ConfigurationNode" + node, e);
		}
		return node.getId();
	}

	@Transactional
	public boolean deleteConfiguration(ConfigurationNode node) throws ConfigurationServiceException {

		try {
			this.getConfigurationDao().delete(node.getId());

			return true;
		} catch (Exception e) {
			logger.error("", e);
			throw new ConfigurationServiceException("Failed to delete ConfigurationNode" + node, e);
		}

	}

	@Transactional
	public boolean deactivateConfiguration(ConfigurationNode node) throws ConfigurationServiceException {

		try {
			node.setDeleted(new Date());
			this.getConfigurationDao().update(node, node.getId());

			return true;
		} catch (Exception e) {
			logger.error("", e);
			throw new ConfigurationServiceException("Failed to deactivate ConfigurationNode" + node, e);
		}
	}

	@Autowired
	@Qualifier("configurationDao")
	public void setConfigurationDao(ConfigurationDao repository) {
		this.configurationDao = repository;
	}

	private ConfigurationDao getConfigurationDao() {
		return configurationDao;
	}

	public List<ConfigurationNode> getAllConfigurations(long nodeId) throws ConfigurationServiceException {
		try {
			return this.getConfigurationDao().getAll();
		} catch (Exception e) {
			logger.error("", e);
			throw new ConfigurationServiceException("Failed to get all ConfigurationNodes" + nodeId, e);
		}
	}

	public List<ConfigurationNode> findConfiguration(ConfigurationNodeCriteria criteria) throws ConfigurationServiceException {

		try {
			// Use a ConfigurationValueCriteria if you want to avoid getting
			// multiple ConfigurationNodes
			if (criteria instanceof ConfigurationValueCriteria) {

				ConfigurationValueCriteria valueCriteria = (ConfigurationValueCriteria) criteria;

				// Limit the select to retrieval of ConfigurationNodes by a
				// name,
				// type, and value key
				String sql = "SELECT e FROM ConfigurationNode e JOIN FETCH e.configurations v WHERE e.name = '" + valueCriteria.getKey() + "' and e.typeEnum = " + valueCriteria.getType().ordinal() + " and v.key = '"
						+ valueCriteria.getSetting() + "'";

				return configurationDao.find(sql);
			}
			String sql = "SELECT e FROM ConfigurationNode e WHERE e.name = '" + criteria.getKey() + "' and e.typeEnum = " + criteria.getType().ordinal() + "";

			return configurationDao.find(sql);
		} catch (Exception e) {
			logger.error("", e);
			throw new ConfigurationServiceException("Failed to find ConfigurationNode" + criteria, e);
		}
	}

	@PersistenceContext
	private EntityManager entityManager;

	@SuppressWarnings("unchecked")
	public List<ConfigurationValue> findConfigurationValue(ConfigurationValueCriteria valueCriteria) throws ConfigurationServiceException {

		try {
			String sql = "SELECT v FROM ConfigurationNode e JOIN e.configurations v WHERE e.name = '" + valueCriteria.getKey() + "' and e.typeEnum = " + valueCriteria.getType().ordinal() + " and v.key = '"
					+ valueCriteria.getSetting() + "'";
			Query list = getEntityManager().createQuery(sql);

			return (List<ConfigurationValue>) list.getResultList();

		} catch (Exception e) {
			logger.error("", e);
			throw new ConfigurationServiceException("Failed to find ConfigurationValue" + valueCriteria, e);
		}
	}

	@Transactional
	public boolean updateConfigurationValue(ConfigurationValue configuration) throws ConfigurationServiceException {

		try {
			getEntityManager().merge(configuration);
			getEntityManager().flush();

			return true;
		} catch (Exception e) {
			logger.error("", e);
			throw new ConfigurationServiceException("Failed to update ConfigurationValue" + configuration, e);
		}
	}

	public ConfigurationValue getConfigurationValue(long valueId) throws ConfigurationServiceException {

		try {
			String sql = "SELECT v FROM ConfigurationValue v WHERE v.id = " + valueId + " ";
			Query list = getEntityManager().createQuery(sql);

			@SuppressWarnings("unchecked")
			List<ConfigurationValue> results = (List<ConfigurationValue>) list.getResultList();
			return results.get(0);
		} catch (Exception e) {
			logger.error("", e);
			throw new ConfigurationServiceException("Failed to get ConfigurationValue " + valueId, e);
		}

	}

	EntityManager getEntityManager() {
		return entityManager;
	}

	void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

}
